高德引擎构建及持续集成技术演进之路
01
背景
支持多团队协作:多团队意味着多操作系统多 IDE ,降低不同操作系统和不同 IDE 下的工程配置的难度是重点要解决的难题之一;
支持多业务线定制:引擎库为手机、车机、开放平台等业务线提供支持,而各个业务线的诉求不同,所以需要具备按功能构建的能力;
支持车机环境:在诸多业务线中,高德地图有一个非常特殊的业务线,即车机(AMAP AUTO)。车机直接面对各大车厂和众多设备商,环境多为定制化,构建工具链各式各样。如果针对每个车机环境都定制一套构建配置文件,那么其维护成本将非常高,所以如何用一套构建配置满足车机的多样化构建需求成为亟需解决的问题;
随着构建次数不断增加,Git 仓库越来越大,代码与依赖库检出越来越慢,极大影响本地开发以及打包效率;
缺乏统一管理,依赖关系混乱,经常出现因为依赖问题而导致的构建失败,或者虽然构建成功但运行时发生错误的情况;
02
本地构建
Make,即 GNU Make ,于1988年发布,是一个用来执行 Makefile 的工具。Makefile 的基本语法包括目标、依赖和命令等。使用过程中,当某些文件变了,只有直接或者间接依赖这些文件的目标才需要重新构建,这样大大提升了编译速度。
编写 Abtor 构建脚本;
解析 Abtor 构建脚本;
检测依赖关系,识别冲突,并从阿里 OSS 上下载所需依赖;
生成CMakeLists.txt,并通过内置的 CMake 生成 Makefile 文件;
编译,链接,生成对应平台的目标文件;
将目标文件发布到阿里 OSS ;
更广泛的跨平台:支持 MacOS 、iOS、Android、 Linux、Windows、QNX 等平台;
有效的多团队协作:较好得与 IDE 结合,并支持一套配置生成不同项目工程,从而达到工程配置一致化;
高定制化:支持工具链及构建参数的灵活定制,并通过内置工具链配置为车机复杂的构建提供强有力的支持;
源码与依赖分离:支持源码依赖与库依赖,源码通过Git管理,构建库存放于阿里云,源码与产物完全分离;
良好的构建性能:快速构建大型项目,从而提高开发效率;
命令简单,降低学习成本,开发者只需熟记 abtorw project [IDE name];
配置文件不会因为 IDE 的增加而迅速膨胀,开发者更换构建命令,比如 abtorw project xcode 或者abtorw project vs2015,即可生成对应的项目工程;
有利于部门间的协作及新人的快速融入,开发者可以根据喜好选择 IDE 进行开发,大大提高开发效率;
内置工具链配置:对于开发者完全透明,他不需要修改任何配置即可构建相应平台的产物;
支持自定义配置插件:开发者按照规则编写配置插件,构建时 Abtor 会检测插件,并根据设置的工具链及构建参数进行构建;
工具链安装:一般由厂商提供,我们会将该工具链安装到基础 Docker 镜像中;
Docker 发布:将镜像发布到 Docker 仓库;
Abtor 适配:一次性适配工具链,并内置配置,开发者可通过 Abtor 版本升级使用该配置;
服务配置更新:由 Jenkins 管理,支持分批更新 Abtor 版本,不影响当下编译需求;
服务监控: 由 Jenkins 管理,定时检测服务状态,异常态的 Docker 服务将自动被重启;
建立 Abtor 服务端,用做库发布,以及处理依赖关系; 每个库在云端构建完,都会把库依赖的版本信息存放于云端数据库中; 本地/云端构建前 Abtor 会解析出所有依赖库的版本信息; 递归查找这些子库对应的依赖信息,即可罗列出所有依赖库的信息; 检测依赖库列表中是否存在不同版本号的相同库名: 如果没有相同库名,则继续执行构建; 如果有相同库名,则说明依赖库之间存在冲突问题,此时中断构建,并显示冲突的库信息,待开发者解决完冲突后方可继续执行构建;
下图是 Abtor 工程项目的目录结构,其中有两类文件是开发者需要关心的,一类是源文件目录(src),一类是 Abtor 核心配置文件(abtor.proj)。
abtor_demo
├── ABTOR
│ └── wrapper
│ ├── abtor-wrapper.properties # 配置文件,可指定Abtor版本信息
│ └── abtor-wrapper.py # 下载Abtor版本并调用Abtor入口函数
├── abtor.proj # Abtor核心配置文件
├── abtorw # Linux/Mac下的初始执行脚本
├── abtorw.bat # Windows下的初始执行脚本
└── src
└── main.c # 要编译的源文件
#!/usr/bin/python
# -*- coding: UTF-8 -*-
# 以下内容为python语法
# 指定编译的源码
header_dirs_list = [abtor_path("include")] # 依赖的头文件目录
binary_src_list = [abtor_path("src/main.c")] # 源码
cflags = " -std=c99 -W -Wall "
cxxflags = " -W -Wall "
# 指定编译二进制
abtor_ccxx_binary(
name = 'demo',
c_flags = cflags,
cxx_flags = cxxflags,
deps = ["add:1.0.0.0"], # 指定依赖的库信息
include_dirs = header_dirs_list;
srcs = binary_src_list
)
采用Python编写,易上手; 抽象类似 abtor_ccxx_binary 等的构建描述,降低使用门槛; 提供诸如 abtor_path 等的内置功能,提高开发效率;
通过以上的对源文件目录组织及 Abtor 核心配置文件编写,我们就完成了项目的Abtor配置化,接着可以通过Abtor内置的命令构建、发布或直接生成项目工程。我们相信,即使开发者不是很精通构建原理,依然可以无障碍地使用Abtor进行构建与发布。
03
持续集成
Amap CI 平台使用Gitlab的Git Webhook实现持续集成。其中,Gitlab 接收开发者的 tag push 事件,回调 CI平台的后台服务,然后后台服务根据构建机器的运行情况进行任务的分发。当构建任务较多时,CI平台会等待直到有构建资源才进行任务的再分配。
通过 Amap CI 平台,我们达到了以下几个目的:
可扩容:所有构建机器通过注册的方式接入,构建机器扩容变得非常容易,减轻构建峰值带来的压力;
可视化:Abtor Server 对于开发者是透明的。CI 平台与 Abtor Server 交互,为开发者提供冲突检查、依赖查看及库下载等可视化功能;
智能化: CI 平台内置标准的 Jenkins Job 构建模板。开发者不感知这些模板,也无须做任何的修改。他们只需要通过 Git 提交一个 tag 信息即可实现全平台的构建,从而实现一键打 tag 构建;
自动化:服务分析 Gitlab hook tag 的 push 信息并拉取代码,然后解析对应的配置文件和要构建的所有平台信息。根据这些信息CI平台分配构建机器,并执行 Abtor 命令进行构建与发布。所有这些皆自动完成;
即时性:构建启动后会发送钉钉消息,消息除了概要信息外还附加了构建的链接等,开发者可以点击链接跟踪进度情况。构建成功或失败也都会发送消息,从而使得开发者可以及时进行下一步工作或处理构建错误;
可扩展:CI平台提供可扩展的对接方式,方便高德或阿里的其它平台对接,比如泰坦平台、CT平台、Aone等,从而实现编码、构建、测试和发布的开发闭环;
在上述目的中,对 Amap CI 平台最重要的是自动化,下面我们重点介绍一下自动化中的整树联动编译。
CI_CONFIG.json DEMO:(json)
{
"mail":"name@alibaba-inc.com", # 邮件通知
"arch":"Android,iOS,Mac,Ubuntu64,Windows", # 构建的平台
"build_vars":"-v -V", # 构建参数
"modules":{ # 构建的模块列表
"amap":{ # 模块名为amap
"features":[ # 功能列表
{
"name":"feature1", # 设置功能名为feature1
"macro":"-DFEATURE_DEMO1=True" # 宏控:FEATURE_DEMO1
},
{
"name":"feature2", # 设置功能名为feature2
"macro":"-DFEATURE_DEMO2=True" # 宏控:FEATURE_DEMO2
}
]
},
"auto":{ # 模块名为auto
"features":[ # 功能列表
{
"name":"feature1", # 设置功能名为feature1
"macro":"-DFEATURE_DEMO1=True" # 宏控:FEATURE_DEMO1
},
{
"name":"feature3", # 设置功能名为feature3
"macro":"-DFEATURE_DEMO3=True" # 宏控:FEATURE_DEMO3
}
]
}
}
}
Amap CI 构建时读取上述文件,解析不同项目中配置的宏,并通过参数传递给 Abtor ,另一方面开发者在代码中利用这些宏进行代码隔离,构建时会根据这些宏选择对应的源码进行编译,从而支持多条业务线不同的需求,达到代码层面的最大复用。
04
未来展望
编辑:黎露(实习生)
往期相关文章:基于LLVM的源码级依赖分析方案的设计与实现
离屏渲染在车载导航中的应用
ArchSummit分享 | 高德地图App架构演化与实践
字节码技术在模块依赖分析中的应用